import os, datetime
from lxml import etree
from enum import Enum
from selenium.webdriver.common.by import By
from support.network.browser import Browser
from support.files.handler.html import HtmlHandler
from support.ai.ollama import Client as OllamaClient
from support.ai.role.definition import *
from support.utils.toolkit import Log

class NetSearch:
    ENGINE= Enum('ENGINE', {
        's360' : 'https://www.so.com/',
        'baidu' : 'https://www.baidu.com/',
        'sougou' :'https://www.sogou.com/',
        'url' : None
    })
    
    HTML_BLOCK = Enum('BLOCK', {
        'div': 1,
    })
    
    ELEMENT_MAP = {
        ENGINE.s360:Enum('S360E', {
            'btn':(By.ID, 'search-button'),
            'input':(By.ID, 'input'),
            'container':(By.XPATH, '//ul[@class="result"]'),
            'item':(By.XPATH, '//li[@class="res-list"]'),
            'next':(By.ID, 'snext')
        }),
        ENGINE.baidu:Enum('SBDE', {
            'btn':(By.ID, 'su'),
            'input':(By.ID, 'kw'),
            'container':(By.ID, 'container'),
            'item':(By.XPATH, '//div[contains(@class, "result")]'),
            'next':(By.XPATH, '//span[contains(text(), "下一页")]/..')
        }),
        ENGINE.sougou:Enum('SOUGOU', {
            'btn':(By.ID, 'stb'),
            'input':(By.ID, 'query'),
            'container':(By.XPATH, '//div[@class="results"]'),
            'item':(By.XPATH, '//div[@class="vrwrap"]'),
            'next':(By.ID, 'sogou_next')
        })
    }
    
    __instance__ = None
    
    def __new__(cls, *args, **kwargs):
        if(not cls.__instance__): cls.__instance__ = object.__new__(cls)
        return cls.__instance__

    def getInstance():
        return QUOTE.__instance__
    
    def __init__(self):
        self.browser = None
        self.handler = HtmlHandler()
        self.ollama = OllamaClient()
        self.assistant = ADAnalyst()
    
    def initBrowser(self, type=Browser.TYPE.chrome, *, host=None, binpath=None, version=None):
        self.browser = Browser(type, host=host, binpath=binpath, version=version)
    
    def __enter__(self):
        return self
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.exit()
        return True

    def exit(self):
        if(self.browser):
            self.browser.exit()

    def __searchBy__(self, engine:ENGINE, keyword, *, timeout:int=10, count:int=10):
        resultList = []
        tabid, html = self.browser.open(engine.value, timeout=timeout, waitConditions=[{"type":Browser.ELEMENT_VISIBLE, "element":NetSearch.ELEMENT_MAP[engine].btn.value}])
        self.browser.input(NetSearch.ELEMENT_MAP[engine].input.value, keyword)
        self.browser.click(NetSearch.ELEMENT_MAP[engine].btn.value)
        while(len(resultList) < count):
            resultList.extend(self.__searchInResult__(engine, count - len(resultList)))
            if((count - len(resultList)) > 0):
                Log.i("Search in next page...")
                self.browser.click(NetSearch.ELEMENT_MAP[engine].next.value)
                self.browser.refresh()
        self.browser.close(tabid)
        return resultList
    
    def __searchInResult__(self, engine:ENGINE, count:int):
        itemList = []
        self.browser.wait([{"type":Browser.ELEMENT_VISIBLE, "element":NetSearch.ELEMENT_MAP[engine].container.value}])
        resultNode = self.browser.findNodeBy(NetSearch.ELEMENT_MAP[engine].container.value)
        for childNode in self.browser.getChildBy(parentNode=resultNode, method=NetSearch.ELEMENT_MAP[engine].item.value):
            self.handler.extract(self.browser.getPageSource(node=childNode))
            context = ""
            for r in self.handler.paragraphing():
                context += "\n".join(r)
            response = self.ollama.chatWith(self.assistant, f"{self.assistant.MISSION_DEF}:{context}", new=True)
            isAd = False
            for kw in self.assistant.KEYWORDS:
                if(response.startswith(kw)):
                    isAd = True
                    break
            if(not isAd):
                itemList.append(context)
            self.handler.clean()
            if(len(itemList) == count):
                break
        return itemList

    def dump(self, html):
        with open(os.path.join(os.path.expanduser('~'),'test.html'), 'w', encoding="utf-8", errors="ignore") as f:
            f.write(html)

    def __openUrl__(self, url):
        tabid, html = self.browser.open(url, timeout=10, waitConditions=[])
        self.browser.close(tabid)
        return html
    
    def search(self, engine, keyword, *, url=None, expectcount:int=10):
        ret = None
        if(self.browser is None):
            Log.i("Browser instance is not created, we will try to connect remote browser")
            self.browser = Browser(Browser.TYPE.chrome, host="http://{}:{}".format(os.environ.get("SELENIUM_HUB_HOST"), os.environ.get("SELENIUM_HUB_PORT")))
        try:
            if(engine == NetSearch.ENGINE.url):
                ret = self.__openUrl__(url)
            else:
                ret = self.__searchBy__(engine, keyword, count=expectcount)
        except Exception as e:
            Log.e("Exception occurred while searching.")
        return ret